#include "task.hpp"
#include <vector>
#include <cstring>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>

class Channel
{
public:
    Channel(int wfd, int SubProcessid, const std::string name)
        : _wfd(wfd), _SubProcessid(SubProcessid), _name(name)
    {
    }

    ~Channel()
    {
    }

    int get_wfd()
    {
        return _wfd;
    }

    int get_SubProcessid()
    {
        return _SubProcessid;
    }

    std::string get_name()
    {
        return _name;
    }
    void Close()
    {
        close(_wfd);
    }
    void Wait()
    {
        int rid = waitpid(_SubProcessid, nullptr, 0);
        if (rid > 0)
        {
            std::cout << "wait success id:" << rid << std::endl;
        }
    }

private:
    int _wfd;
    int _SubProcessid;
    std::string _name;
};

void work()
{
    while (true)
    {
        int command = 0;
        int n = read(0, &command, sizeof(command));
        if (n > 0)
        {
            std::cout << "pid is " << getpid() << " handle task" << std::endl;
            // 执行任务
            ExecuteTask(command);
            std::cout << std::endl;
        }
        else if (n == 0)
        {
            // 读到0说明写端关闭了，则把读端也关闭
            std::cout << "Sub Process: id is " << getpid() << " quit" << std::endl;
            break;
        }
        else
        {
            std::perror("read");
            break;
        }
    }
}

int SelectChannel(int channels_num)
{
    static int next = 0;
    int number = next;
    next++;
    next %= channels_num;
    return number;
}

void SendTask(int task_command, Channel &channel)
{
    write(channel.get_wfd(), &task_command, sizeof(task_command));
}

void ctrlProcessOnce(std::vector<Channel> &channels)
{
    sleep(1);
    // 选择一个任务
    int task_command = SelectTask();
    // 选择一个信道和子进程
    int channel_num = SelectChannel(channels.size());
    // 给指定信道发送任务
    SendTask(task_command, channels[channel_num]);
    std::cout << "taskcommand:" << task_command << " channel name:" << channels[channel_num].get_name() << " SubProcessid:" << channels[channel_num].get_SubProcessid() << std::endl;
}

void ctrlProcess(std::vector<Channel> channels, int time = -1)
{
    if (time > 0)
    {
        while (time--)
        {
            ctrlProcessOnce(channels);
        }
    }
    else
    {
        while (true)
        {
            ctrlProcessOnce(channels);
        }
    }
}

void CreateProcessPool(int num, std::vector<Channel> *channels, task_t task)
{
    for (int i = 0; i < num; i++)
    {
        // 创建管道
        int pipefd[2];
        int n = pipe(pipefd);
        if (n < 0)
            exit(-1);
        // 创建子进程
        pid_t id = fork();
        if (id == 0)
        {
            if(!channels->empty())
            {
                for(auto& e:*channels)
                {
                    e.Close();
                }

            }
            // 子进程 read
            close(pipefd[1]);
            dup2(pipefd[0], 0);
            task();
            close(pipefd[0]);
            exit(0);
        }
        // father
        close(pipefd[0]);
        std::string channel_name = "Channel-" + std::to_string(i);
        channels->push_back(Channel(pipefd[1], id, channel_name));
    }
}

void CleanChannel(std::vector<Channel> &Channels)
{
    // for (auto &e : Channels)
    // {
    //     e.Close();
    // }

    // for (auto &e : Channels)
    // {
    //     e.Wait();
    // }

    for (auto &e : Channels)
    {
        e.Close();
        e.Wait();
    }
}

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        std::cout << "使用错误，请输入创建的个数！" << std::endl;
        exit(-1);
    }

    int num = std::stoi(argv[1]);
    DownLoadTsak();
    std::vector<Channel> Channels;

    // 创建信道和子进程
    CreateProcessPool(num, &Channels, work);
    // 通过channel控制子进程
    ctrlProcess(Channels, 5);
    // 清理
    CleanChannel(Channels);
    return 0;
}